package analiseSemantica;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Stack;

public class TabelaDeSimbolo {

	HashMap map = new HashMap(); // hashing da tabela
	Stack st = new Stack(); // pilha do escopo
	Integer escopo = new Integer(0);

	public TabelaDeSimbolo() {
		st.push(escopo);
		// teste();

	}

	public void insert(Simbolo sbl) {
		st.add(sbl);
		printStack();
		LinkedList list;
		String id = sbl.getIdenticador();
		System.out.println("\nInsert: "+ id);
		
		if (map.containsKey(id) == true) {
			list = (LinkedList) map.get(id);
			list.addFirst(sbl);
			map.put(id, list);
		} else {
			list = new LinkedList();
			list.addFirst(sbl);
			map.put(id, list);
		}
	}

	public void criarEscopo() {
		this.escopo = escopo + 1;
		st.push(escopo); // topo da pilha + 1
	}

	public void remove() {
		//  
		Object ob;
		Simbolo sblAux;
		ob = st.pop();
		LinkedList list;
		String id;
		while (ob instanceof Simbolo) {
			sblAux = (Simbolo) ob;
			id = sblAux.getIdenticador();
			list = (LinkedList) map.get(id);
			list.removeFirst();
			System.out.println("remove: "+ id);
			if (!list.isEmpty()) {
				map.put(id, list);
			}
			ob = st.pop();

		}

		escopo--;

	}

	public boolean compararParam(Simbolo sb) {
		if (sb.getNumParametro() == sb.getNumArgumentos())
			return true;
		else
			return false;
	}

	public boolean verificarExiste(String s) {
		if (map.containsKey(s))
			return true;
		else
			return false;
	}

	public boolean verificarExiste(String s, int escopo) {

		if (map.containsKey(s)) {
			
			Simbolo simbolo = this.pegarSimbolo(s);

			if (simbolo!=null && simbolo.getEscopo() <= escopo) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public int pegarType(String s) {
		Simbolo aux;
		LinkedList list;
		if (map.containsKey(s)) {
			list = (LinkedList) map.get(s);
			if (!list.isEmpty()) {
				aux = (Simbolo) list.getFirst();
				return aux.getTipo();
			}
		}
		return -1;
	}
	public String pegarStipo(String s) {
		Simbolo aux;
		LinkedList list;
		if (map.containsKey(s)) {
			list = (LinkedList) map.get(s);
			if (!list.isEmpty()) {
				aux = (Simbolo) list.getFirst();
				return aux.getStipo();
			}
		}
		return null;
	}

	public Simbolo pegarSimbolo(String s) {
		Simbolo aux = null;
		
		//this.print(s);
		LinkedList list;
		if (map.containsKey(s)) {
			list = (LinkedList) map.get(s);
			Iterator i = list.iterator();
			
			if(i.hasNext()){
				aux = (Simbolo) list.getFirst();
			
			}
					
			return aux;
		}
		return null;
	}

	public boolean verificarInsert(Simbolo sbl) {

		if (map.containsKey(sbl.getIdenticador())) {
			LinkedList list = (LinkedList) map.get(sbl.getIdenticador());
			if (!list.isEmpty()) {
				Simbolo aux = (Simbolo) list.getFirst();

				if (sbl.getEscopo() == aux.getEscopo()) {
					return false;
				} else {
					return true;
				}
			}
		}
		return true;
	}

	public void print(String id) {
		LinkedList listprint;
		listprint = (LinkedList) map.get(id);
		Iterator i = listprint.iterator();
		System.out.println("print - "+map.containsKey(id));
		int j = listprint.size();
		while (i.hasNext()) {
			Simbolo sb = (Simbolo) i.next();
			System.out.println("Elemento: " + j-- + " - ID: " + sb.getIdenticador() +
                    " - Tipo : " + sb.getTipo() + "    - escopo : " + sb.getEscopo());
		}
	}

	public Integer getEscopo() {
		return escopo;
	}

	public void setEscopo(Integer escopo) {
		this.escopo = escopo;
	}

	public HashMap getMap() {
		return map;
	}

	public void setMap(HashMap map) {
		this.map = map;
	}

	public Stack getSt() {
		return st;
	}

	public void setSt(Stack st) {
		this.st = st;
	}

	public void printStack() {
		Simbolo sbl;

		st.listIterator();
		Iterator i = st.iterator();

		Object ob;
		Simbolo sb;
		while (i.hasNext()) {
			ob = i.next();
			if (ob instanceof Integer) {
				System.out.print(ob.toString() + " > ");
			} else {
				sb = (Simbolo) ob;
				System.out.print(sb.getIdenticador() + " > ");
			}
		}

	}

	public void teste() {

		Simbolo sb1 = new Simbolo(1, "id 1", 1, 1);
		System.out.println();
		insert(sb1);
		// printStack();
		// print(sb1.getIdenticador());
		criarEscopo();
		System.out.println();
		System.out.println("\n\n primeiro TESTE");
		Simbolo sb2 = new Simbolo(2, "id 1", 2, 1);
		insert(sb2);
		print(sb1.getIdenticador());

		remove();
		System.out.println("\n\n SEgundo TESTE");
		print(sb1.getIdenticador());

		/*
		 * Simbolo sb3 = new Simbolo("id 3", "int", "2", 1); insert(sb3);
		 * 
		 * Simbolo sb4 = new Simbolo("id 4", "int", "2", 1); insert(sb4); //
		 * print(sb2.getIdenticador());
		 * 
		 * printStack(); System.out.println("\n"); System.out.println("\n");
		 * System.out.println("\n");
		 * System.out.println(map.containsKey("id 1"));
		 * System.out.println(map.containsKey("id 2"));
		 * System.out.println(map.containsKey("id 3"));
		 * System.out.println(map.containsKey("id 4")); remove(); printStack();
		 * print(sb1.getIdenticador());
		 * System.out.println(map.containsKey("id 1"));
		 * System.out.println(map.containsKey("id 2"));
		 * System.out.println(map.containsKey("id 3"));
		 * System.out.println(map.containsKey("id 4"));
		 */
	}
}
